package ace.cmp.util;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * @author Caspar 反射工具
 */
public final class AceReflectionUtils {
  /**
   * 获取接口上的泛型T
   *
   * @param cls   接口
   * @param index 泛型索引
   */
  public static Class<?> getInterfaceGeneric(Class<?> cls, int index) {
    Type[] types = cls.getGenericInterfaces();
    ParameterizedType parameterizedType = (ParameterizedType) types[index];
    Type type = parameterizedType.getActualTypeArguments()[index];
    return checkType(type, index);
  }

  /**
   * 获取父类上的泛型
   *
   * @param cls   接口
   * @param index 泛型索引
   */
  public static Class<?> getClassGeneric(Class<?> cls, int index) {
    Type type = cls.getGenericSuperclass();
    if (type instanceof ParameterizedType) {
      ParameterizedType parameterizedType = (ParameterizedType) type;
      Type actType = parameterizedType.getActualTypeArguments()[index];
      return checkType(actType, index);
    } else {
      String className = type == null ? "null" : type.getClass().getName();
      throw new IllegalArgumentException(
          "Expected a Class, ParameterizedType" + ", but <" + type + "> is of type " + className);
    }
  }

  private static <T> Class<T> checkType(Type type, int index) {
    if (type instanceof Class) {
      return (Class<T>) type;
    } else if (type instanceof ParameterizedType) {
      ParameterizedType pt = (ParameterizedType) type;
      Type t = pt.getActualTypeArguments()[index];
      return checkType(t, index);
    } else {
      String className = type == null ? "null" : type.getClass().getName();
      throw new IllegalArgumentException(
          "Expected a Class, ParameterizedType" + ", but <" + type + "> is of type " + className);
    }
  }
}
